package com.octopus.yangj.customized.controller;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ValidationUtils;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.octopus.kernal.controller.AbstractCustomizedController;
import com.octopus.kernal.controller.SearchOperator;
import com.octopus.kernal.ui.builder.DetailTableBuilder;
import com.octopus.kernal.ui.element.BaseElement;
import com.octopus.kernal.ui.element.CheckboxElement;
import com.octopus.yangj.customized.service.CustomizedEventService;
import com.octopus.yangj.customized.service.LogService;
import com.octopus.yangj.generated.controller.EventValidator;
import com.octopus.yangj.generated.controller.SearchEventCommand;
import com.octopus.yangj.generated.model.ClientStruct;
import com.octopus.yangj.generated.model.EventExecuteStruct;
import com.octopus.yangj.generated.model.EventStruct;
import com.octopus.yangj.generated.model.ExecuteUnitStruct;
import com.octopus.yangj.generated.service.ClientService;
import com.octopus.yangj.generated.service.EventExecuteService;
import com.octopus.yangj.generated.service.ExecuteUnitService;
import com.octopus.yangj.util.EventExecuteStatus;
import com.octopus.yangj.util.EventStatus;

@Controller
@RequestMapping("/event/x")
public class CustomizedEventController extends AbstractCustomizedController<EventStruct, SearchEventCommand, Long>{
	
    @Autowired
    protected CustomizedEventService eventService;
    
    @Autowired
    protected ClientService clientService;
    
    @Autowired
    protected EventExecuteService eventExecuteService;
    
    @Autowired
    protected ExecuteUnitService executeUnitService;
    
    @Autowired
    private DetailTableBuilder<EventStruct> detailTableBuilder;
    
    @Autowired
    private EventValidator eventValidator;
    
    @Autowired
    private LogService logService;
    
    @RequestMapping(value = "/view.o", method = RequestMethod.GET)
    public String viewCustomized(Model model, HttpServletRequest request,
        @RequestParam
        Long id,
        @ModelAttribute
        EventStruct entity) {
    	return "forward:/event/view.o";
    }
    
	@Override
	public String query(Model model, HttpServletRequest request, SearchEventCommand searchCommand) {
		String status = request.getParameter("status");
		boolean statsFromUri = false;
		if(searchCommand.getOperator() == null){
			searchCommand.setOperator(new EventStruct());
		}
		if(StringUtils.isNotBlank(status)){
			statsFromUri = true;
			searchCommand.getEntity().setStatus(status);
			searchCommand.getOperator().setStatus(String.valueOf(SearchOperator.EQUAL.ordinal()));
	        request.getSession().setAttribute("eventCommand", searchCommand.getEntity());
	        request.getSession().setAttribute("eventOperator", searchCommand.getOperator());

		}
		Object eventCommand = request.getSession().getAttribute("eventCommand");
		if(eventCommand != null)
			status =  ((EventStruct)eventCommand).getStatus();
		String title = "label.event.title";
        if(EventStatus.ASSIGNED.getStatus().equals(status)){
        	title = "label.event.action.list.assigned";
        }else if(EventStatus.CREATED.getStatus().equals(status)){
        	title = "label.event.action.list.created";
        	searchCommand.getEntity().setStatus(EventStatus.VALIDATED.getStatus());
        	searchCommand.getOperator().setStatus(String.valueOf(SearchOperator.EQUAL.ordinal()));
        }else if(EventStatus.EXECUTED.getStatus().equals(status)){
        	title = "label.event.action.list.executed";
        }else if(EventStatus.INVALIDATED.getStatus().equals(status)){
        	title = "label.event.action.list.invalidated";
        }else if(EventStatus.VALIDATED.getStatus().equals(status)){
        	title = "label.event.action.list.validated";
        	if(statsFromUri){
	        	searchCommand.getEntity().setStatus(EventStatus.INVALIDATED.getStatus());
	        	searchCommand.getOperator().setStatus(String.valueOf(SearchOperator.NOTEQUAL.ordinal()));
        	}
        }else if(EventStatus.CLOSED.getStatus().equals(status)){
        	title = "label.event.action.list.closed";
        }
        request.setAttribute("customizedTitle", eventValidator.getMessageSource().getMessage(title, new Object[] { }, LocaleContextHolder.getLocale()));
		return null;
	}
    
    @RequestMapping(value = "/create_from_client.o", method = RequestMethod.GET)
    public String createFromClient(Model model, HttpServletRequest request,
        @ModelAttribute
        EventStruct entity, BindingResult errors) {
    	if(!SecurityUtils.getSubject().isPermitted("event:create")){
    		return "redirect:/common/unauthorized.o";
    	}
    	entity.setId(null);
    	String clientId = request.getParameter("cid");
    	if(clientId != null){
    		entity.setClientId(Long.valueOf(clientId));
    	}
    	ClientStruct client = clientService.getEntity(entity.getClientId());
        model.addAttribute("ACTION", "create");
        entity.setTelphone(client.getTelphone());
        entity.setEventDate(new Date());
		List<String> disabled = new ArrayList<String>();
		disabled.add("status");
		disabled.add("result");
		disabled.add("mark");
		disabled.add("feedback");
        model.addAttribute("ACTION", "create");
        request.setAttribute("eventDetailTable", detailTableBuilder.build(request, entity, eventValidator.getMessageSource(), false, null, disabled));
        request.setAttribute("eventDetailButtons", detailTableBuilder.buildButton(request, entity, eventValidator.getMessageSource(), false));
        return "customized/event/edit";
    }
    
    @RequestMapping(value = "/create_from_client.o", method = RequestMethod.POST)
    public String createFromClientSave(Model model, HttpServletRequest request,
        @ModelAttribute
        EventStruct entity, BindingResult errors) {
    	if(!SecurityUtils.getSubject().isPermitted("event:create")){
    		return "redirect:/common/unauthorized.o";
    	}
    	entity.setId(null);
    	String clientId = request.getParameter("cid");
    	if(clientId != null){
    		entity.setClientId(Long.valueOf(clientId));
    	}
    	ClientStruct client = clientService.getEntity(entity.getClientId());
    	String action = request.getParameter("ACTION");
    	if("submit".equals(action) || "create_validate_event".equals(action)){
            eventValidator.validate(entity, errors);
            if (errors.hasErrors()) {
            	return this.createFromClient(model, request, entity, errors);
            }
    		if(StringUtils.isBlank(entity.getName())){
    	        entity.setName(client.getName() + " - [" + entity.getEventDateStr() + "]");
    		}
            try {
            	entity.setStatus(EventStatus.CREATED.getStatus());
            	if("create_validate_event".equals(action)){
            		entity.setStatus(EventStatus.VALIDATED.getStatus());
            		eventService.createEntity(entity);
            		logService.log("event", "create", entity.getName());
            		logService.log("event", "validate", entity.getName());
            	}else{
            		eventService.createEntity(entity);
            		logService.log("event", "create", entity.getName());
            	}
            } catch (DataIntegrityViolationException _x) {
                _x.printStackTrace();
                errors.rejectValue("id", "error.common.model.exist", "The entity has already existed.");
                return this.createFromClient(model, request, entity, errors);
            }
            return ("redirect:/event/query.o");
    	}else{
    		entity.setName(null);
    	}
        return ("redirect:/event/query.o");
    }
    
    @RequestMapping(value = "/validate.o")
    public String validateEvent(Model model, HttpServletRequest request,
            @RequestParam
            Long id,
            @ModelAttribute
            SearchEventCommand searchCommand) {
    	if(!SecurityUtils.getSubject().isPermitted("event:validate")){
    		return "redirect:/common/unauthorized.o";
    	}
        String offset = request.getParameter("pager.offset");
        if (StringUtils.isNotBlank(offset)) {
            offset = "?pager.offset=" + offset;
        } else {
            offset = "";
        }
    	EventStruct entity2 = eventService.getEntity(id);
    	entity2.setStatus(entity2.getPreStatus());
    	entity2.setPreStatus(null);
    	eventService.updateEntity(entity2);
    	logService.log("event", "validate", entity2.getName());
    	return ("redirect:/event/query.o"+ offset);
    }
    
    @RequestMapping(value = "/invalidate.o")
    public String invalidateEvent(Model model, HttpServletRequest request,
            @RequestParam
            Long id,
            @ModelAttribute
            SearchEventCommand searchCommand) {
    	if(!SecurityUtils.getSubject().isPermitted("event:invalidate")){
    		return "redirect:/common/unauthorized.o";
    	}
        String offset = request.getParameter("pager.offset");
        if (StringUtils.isNotBlank(offset)) {
            offset = "?pager.offset=" + offset;
        } else {
            offset = "";
        }
    	EventStruct entity2 = eventService.getEntity(id);
    	entity2.setPreStatus(entity2.getStatus());
    	entity2.setStatus(EventStatus.INVALIDATED.getStatus());
    	eventService.updateEntity(entity2);
    	logService.log("event", "invalidate", entity2.getName());
    	return ("redirect:/event/query.o"+ offset);
    }
    
    @RequestMapping(value = "/assign.o", method = RequestMethod.GET)
    public String assign(Model model, HttpServletRequest request,
        @RequestParam
        Long id,
        @ModelAttribute
        EventStruct entity) {
        model.addAttribute("ACTION", "assign");
        EventStruct entity2 = eventService.getEntity(id);
        try {
            BeanUtils.copyProperty(entity, "attributeValues", entity2 .getAttributeValues());
        } catch (Exception _x) {
            _x.printStackTrace();
        }
        request.setAttribute("eventDetailTable", detailTableBuilder.build(request, entity, eventValidator.getMessageSource(), true));
        CheckboxElement checkbox = new CheckboxElement();
        checkbox.setList(true);
        checkbox.setId("executeUnit");
        checkbox.setName(checkbox.getId());
        checkbox.setType("ExecuteUnit");
        checkbox.setLabelProperty("name");
        checkbox.setLayout(3);
        checkbox.setEntitiesScrope(new ArrayList<Object>());
        checkbox.getEntitiesScrope().addAll((executeUnitService.getEntitiesAll()));
        Set<ExecuteUnitStruct> units = new HashSet<ExecuteUnitStruct>();
        if(entity2.getThirdCategory()!= null && entity2.getThirdCategory().getExecuteUnits() != null && entity2.getThirdCategory().getExecuteUnits().size() > 0){
        	units.addAll(entity2.getThirdCategory().getExecuteUnits());
        }else if(entity2.getSecondCategory()!= null && entity2.getSecondCategory().getExecuteUnits() != null && entity2.getSecondCategory().getExecuteUnits().size() > 0){
        	units.addAll(entity2.getSecondCategory().getExecuteUnits());
        }else if(entity2.getFirstCategory()!= null && entity2.getFirstCategory().getExecuteUnits() != null && entity2.getFirstCategory().getExecuteUnits().size() > 0){
        	units.addAll(entity2.getFirstCategory().getExecuteUnits());
        }
        checkbox.setValue(units);
        request.setAttribute("executeUnitTable", checkbox.toString());
        return "customized/event/assign";
    }
    
    @RequestMapping(value = "/assign.o", method = RequestMethod.POST)
    public String saveAssign(Model model, HttpServletRequest request,
            @RequestParam
            Long id,
            @ModelAttribute
            EventStruct entity, BindingResult errors) {
        String offset = request.getParameter("pager.offset");
        if (StringUtils.isNotBlank(offset)) {
            offset = "?pager.offset=" + offset;
        } else {
            offset = "";
        }
        String[] unitIds = request.getParameterValues("executeUnitId");
        if(unitIds == null || unitIds.length == 0){
            ValidationUtils.rejectIfEmptyOrWhitespace(errors, "executes", "error.common.field.empty", 
            		new Object[] {eventValidator.getMessageSource().getMessage("label.execute_unit.model", new Object[] { }, LocaleContextHolder.getLocale())}, "Please specify at least one Execute Unit.");
            return assign(model, request, id, entity);
        }
        List<String> errs = eventService.assign(id, unitIds);
        EventStruct event = eventService.getEntity(id);
        logService.log("event", "assign", event.getName());
        if(errs == null || errs.size() == 0){
        	return ("redirect:/event/query.o"+ offset);
        }else{
        	model.addAttribute("ACTION", "assign");
        	request.setAttribute("errs", errs);
        	return ("customized/event/back");
        }
    }
    
    @RequestMapping(value = "/progress.o", method = RequestMethod.GET)
    public String progress(Model model, HttpServletRequest request,
        @RequestParam
        Long id,
        @ModelAttribute
        EventStruct entity) {
    	eventService.getFeedbackFromUnit(id);
    	return "redirect:/event/view.o?id=" + id;
    }
    
    @RequestMapping(value = "/close.o")
    public String closeEvent(Model model, HttpServletRequest request,
            @RequestParam
            Long id) {
    	if(!SecurityUtils.getSubject().isPermitted("event:close")){
    		return "redirect:/common/unauthorized.o";
    	}
        String offset = request.getParameter("pager.offset");
        if (StringUtils.isNotBlank(offset)) {
            offset = "?pager.offset=" + offset;
        } else {
            offset = "";
        }
    	EventStruct entity = eventService.getEntity(id);
    	entity.setStatus(EventStatus.CLOSED.getStatus());
    	eventService.updateEntity(entity);
    	logService.log("event", "close", entity.getName());
    	return ("redirect:/event/query.o"+ offset);
    }
    
	@Override
	public String create(Model model, HttpServletRequest request, EventStruct entity) {
		entity.setEventDate(new Date());
		List<String> disabled = new ArrayList<String>();
		disabled.add("status");
		disabled.add("result");
		disabled.add("mark");
		disabled.add("feedback");
        model.addAttribute("ACTION", "create");
        request.setAttribute("eventDetailTable", detailTableBuilder.build(request, entity, eventValidator.getMessageSource(), false, null, disabled));
        request.setAttribute("eventDetailButtons", detailTableBuilder.buildButton(request, entity, eventValidator.getMessageSource(), false));
        return "customized/event/edit";
	}

	@Override
	public String saveCreate(Model model, HttpServletRequest request, EventStruct entity,
			BindingResult errors) {
		if(StringUtils.isBlank(entity.getName())){
			ClientStruct client = clientService.getEntity(entity.getClientId());
	        entity.setName(client.getName() + " - [" + entity.getEventDateStr() + "]");
		}
		entity.setStatus(EventStatus.CREATED.getStatus());
		String action = request.getParameter("ACTION");
		if("create_validate_event".equals(action)){
			entity.setStatus(EventStatus.VALIDATED.getStatus());
		}
		return null;
	}

	@Override
	public String saveEdit(Model model, HttpServletRequest request, Long id, EventStruct entity,
			BindingResult errors) {
		if(StringUtils.isBlank(entity.getName())){
			ClientStruct client = clientService.getEntity(entity.getClientId());
			entity.setName(client.getName() + " - [" + entity.getEventDateStr() + "]");
		}
		if(EventStatus.ASSIGNED.getStatus().equals(entity.getStatus())){
			boolean allexecuted = false;
			boolean hasassigned = false;
			EventStruct event = eventService.getEntity(id);
			Set<EventExecuteStruct> executes = event.getExecutes();
			if(executes != null && executes.size() > 0){
				allexecuted = true;
				hasassigned = true;
				for(EventExecuteStruct execute : executes){
					execute.setEvent(entity);
					String response = request.getParameter("execute.response." + execute.getId());
					String department = request.getParameter("execute.department." + execute.getId());
					String progress = request.getParameter("execute.progress." + execute.getId());
					String preHandleImgUrl = request.getParameter("execute.preHandleImgUrl." + execute.getId());
					String postHandleImgUrl = request.getParameter("execute.postHandleImgUrl." + execute.getId());
					execute.setDepartment(department);
					execute.setProgress(progress);
					execute.setPreHandleImgUrl(preHandleImgUrl);
					execute.setPostHandleImgUrl(postHandleImgUrl);
					execute.setResponse(response);
					String checked = request.getParameter("execute.executed." + execute.getId());
					if("true".equals(checked)){
						EventExecuteStruct exe = eventExecuteService.getEntity(execute.getId());
						if(exe.getExecuted() == null || !exe.getExecuted()){
							execute.setExecuted(true);
							execute.setProgress(null);
							execute.setStatus(EventExecuteStatus.EXECUTED.getStatus());
							execute.setExecuteDate(new Date());
						}
					}else{
						allexecuted = false;
						execute.setExecuted(false);
						execute.setStatus(EventExecuteStatus.PENDING_OPERATOR.getStatus());
						execute.setExecuteDate(null);
						entity.setExecuteDate(null);
					}
				}
			}
			if(allexecuted && !event.getStatus().equals(EventStatus.EXECUTED.getStatus())){
				entity.setStatus(EventStatus.EXECUTED.getStatus());
				entity.setExecuteDate(new Date());
				logService.log("event", "execute", entity.getName());
			}else if(!allexecuted && hasassigned){
				//entity.setStatus(EventStatus.ASSIGNED.getStatus());
			}
			entity.setExecutes(event.getExecutes());
		}else if(EventStatus.EXECUTED.getStatus().equals(entity.getStatus())){
			eventService.sendClientFeedback(entity);
		}
		return null;
	}
	
	@Override
	public String edit(Model model, HttpServletRequest request, Long id, EventStruct entity) {
		if(entity.getExecutes() != null){
			for(EventExecuteStruct execute : entity.getExecutes()){
				String name = execute.getExecuteUnit().getName();
				execute.getExecuteUnit().setName(BaseElement.getTranslationValue(name));
			}
		}
		List<String> disabled = new ArrayList<String>();
		if(EventStatus.CREATED.getStatus().equals(entity.getStatus())){
			
		}else if(EventStatus.VALIDATED.getStatus().equals(entity.getStatus())){
			disabled.add("status");
			disabled.add("result");
			disabled.add("mark");
			disabled.add("feedback");
		}else if(EventStatus.ASSIGNED.getStatus().equals(entity.getStatus())){
			disabled.add("client");
			disabled.add("name");
			disabled.add("status");
			disabled.add("externalId");
			disabled.add("telphone");
			disabled.add("eventDate");
			disabled.add("address");
			disabled.add("assignDate");
			disabled.add("executeDate");
			disabled.add("firstCategory");
			disabled.add("secondCategory");
			disabled.add("thirdCategory");
			disabled.add("description");
			disabled.add("mark");
			disabled.add("feedback");
		}else if(EventStatus.INVALIDATED.getStatus().equals(entity.getStatus())){
			
		}else if(EventStatus.EXECUTED.getStatus().equals(entity.getStatus())){
			disabled.add("client");
			disabled.add("name");
			disabled.add("status");
			disabled.add("externalId");
			disabled.add("telphone");
			disabled.add("eventDate");
			disabled.add("address");
			disabled.add("assignDate");
			disabled.add("executeDate");
			disabled.add("firstCategory");
			disabled.add("secondCategory");
			disabled.add("thirdCategory");
			disabled.add("description");
		}else if(EventStatus.CLOSED.getStatus().equals(entity.getStatus())){
			
		}
        request.setAttribute("eventDetailTable", detailTableBuilder.build(request, entity, eventValidator.getMessageSource(), false, null, disabled));
        request.setAttribute("eventDetailButtons", detailTableBuilder.buildButton(request, entity, eventValidator.getMessageSource(), false));
        return "customized/event/edit";
	}
	
	@Override
	public String view(Model model, HttpServletRequest request, Long id, EventStruct entity) {
		if(entity.getExecutes() != null){
			for(EventExecuteStruct execute : entity.getExecutes()){
				String name = execute.getExecuteUnit().getName();
				execute.getExecuteUnit().setName(BaseElement.getTranslationValue(name));
			}
		}
		return null;
	}
}
